聽前輩說,「this」在JavaScript裡面是一個大坑。
前面有提過「this」在事件監聽中,不考慮事件冒泡的情況下,this就等同是e.target,但是如果是被事件冒泡觸發的this則為e.currentTarget。
現在來談談「this」在其他地方要注意的事情。
首先要記住這句話,只要理解這個原則,大部分遇到「this」的狀況都可以輕鬆掌握:
「this代表的是function執行時所屬的物件,而不是function本身」
「this」是在函式被呼叫的時候被自動生成的內部物件,this不等於function,隨著呼叫函示的物件不同,「this」所指向的值也不同。
沒有特別指定this的情況下,this預設綁定(Default Binding)「全域物件」,也就是window。
但在ES5的嚴格模式下,禁止this自動指定為全域物件,這點要特別注意。
var seven = "江南七怪";
console.log(window.seven); //"江南七怪"
function monster(){
console.log(this.seven + "脾氣古怪");
}
monster(); //"江南七怪脾氣古怪"
var obj = {
seven : "七喜汽水",
func: monster
}
obj.func(); //"七喜汽水脾氣古怪"
所以在全域環境中直接呼叫monster()函式時,this.seven是指向全域變數的var seven = "江南七怪";當monster()作為obj物件func屬性的方法的時候,this.seven會指向obj物件的seven屬性"七喜汽水"。
var seven = "江南七怪";
var call = function() {
console.log(this.seven);
}
var soda = function(){
let seven = "七喜汽水";
this.call();
}
soda(); //"江南七怪"
soda()透過this.call()來叫用call(),這時call()裡面的this.seven是指向全域變數的seven,所以得到的結果是"江南七怪"。
在JavaScript有三種方式可以強制指定this給function,這種方式也叫「顯式綁定」,分別是:
先來說說.call與.apply
function funcA(){
//做某件大事
}
funcA.call(context, arg1, arg2...)
funcA.apply(context,[arg1,arg2...])
上面的程式碼式使用.call與.apply去呼叫執行funcA,第一個參數context為所帶入的物件,也就是強制用那個物件來當成function執行時的物件。
.call與.apply作用一樣,差別在.apply第一個參數(帶入的物件)之後的參數以陣列方式傳入,而.call則是使用逗號隔開。
let kuo = {
name: "郭靖",
wife: "黃蓉"
}
let yung = {
name: "楊過",
wife: "小龍女"
}
function funcA(){
console.log(`${this.name}的老婆是${this.wife}`)
}
funcA.call(kuo) //郭靖的老婆是黃蓉
funcA.apply(yung) //楊過的老婆是小龍女
funcA.call(null,"周伯通","瑛姑")//的老婆是undefined
我們可以看見this.name與this.wife綁定到帶入的物件上。而this隨著所帶入的物件不同,指向也會動態地改變。
而bind的用法如下:
let kuo = {
name: "郭靖",
wife: "黃蓉"
}
let yung = {
name: "楊過",
wife: "小龍女"
}
function funcA(){
console.log(`${this.name}的老婆是${this.wife}`)
}
let kuoWife = funcA.bind(kuo);
kuoWife() //郭靖的老婆是黃蓉
let yungWife = funcA.bind(yung);
yungWife() //楊過的老婆是小龍女
藉由‵let kuoWife = funcA.bind(kuo) ‵也可以把this指向所帶入的物件。
其實以上的應用,萬變不離其宗,只要記得:「this代表的是function執行時所屬的物件,而不是function本身」